package System;

import java.util.ArrayList;
import java.util.HashMap;

public class Main {

	private ArrayList<User> users;
	private ArrayList<String> idUsers;
	private ArrayList<Item> items;
	private ArrayList<RequestItem> requests;
	private ArrayList<Borrowing> borrowings;
	private IdGenerator idGen;
	private HashMap<String, String[]> offTopicMessages;
	private HashMap<String, String[]> borrowingMessages;
	private HashMap<String, String[]> allMessages;

	public Main() {
		users = new ArrayList<User>();
		items = new ArrayList<Item>();
		idGen = new IdGenerator();
		idUsers = new ArrayList<String>();
		offTopicMessages = new HashMap<String, String[]>();
		borrowingMessages = new HashMap<String, String[]>();
		allMessages = new HashMap<String, String[]>();

		setRequests(new ArrayList<RequestItem>());
	}

	/**
	 * Cadastra um novo usuario no Sistema
	 * 
	 * @param login
	 * @param userName
	 * @param address
	 * @return
	 * @throws Exception
	 */
	public String newUser(String login, String userName, String address)
			throws Exception {
		String newUserID = idGen.generateId();

		for (User u : users) {
			if (u.getLogin().equals(login)) {
				throw new Exception("Já existe um usuário com este login");
			}
			if (u.getUserID().equals(newUserID)) {
				newUserID = idGen.generateId();
			}
		}

		User user = new User(login, userName, address);

		user.setUserID(newUserID);
		users.add(user);
		idUsers.add(newUserID);

		return user.getUserID();
	}

	/**
	 * Abre uma nova sessao no sistema.
	 * 
	 * @param login
	 * @return
	 * @throws Exception
	 */
	public String openSession(String login) throws Exception {
		if (login == null || login.equals("")) {
			throw new Exception("Login inválido");
		}
		for (User u : users) {
			if (u.getLogin().equals(login)) {
				String idSession = idGen.generateId();
				u.setUserID(idSession);

				return idSession;
			}
		}

		throw new Exception("Usuário inexistente");
	}

	/**
	 * registra um item para um determinado usu�rio.
	 * 
	 * @param IDSession
	 * @param name
	 * @param description
	 * @param itemType
	 * @return
	 * @throws Exception
	 */
	public String itemRegister(String IDSession, String name,
			String description, String category) throws Exception {

		if (IDSession == null || IDSession.equals("")) {
			throw new Exception("Sessão inválida");
		}

		for (User u : users) {

			if (u.getUserID().equals(IDSession)) {
				String itemID = idGen.generateId();
				for (Item i : items) {
					if (i.getItemID().equals(itemID)) {
						itemID = idGen.generateId();
					}
				}

				Item item = new Item(name, description, category);

				item.setItemID(itemID);
				items.add(item);
				u.addMyItem(item);

				return item.getItemID();

			}

		}

		throw new Exception("Sessão inexistente");

	}

	public String searchUserNameById(String id) {
		for (User u : users) {

			if (u.getUserID().equals(id)) {

				return u.getUserName();
			}
		}

		return "Usuario nao encontrado";
	}

	public String getUserIDByLogin(String login) {
		for (User u : users) {
			if (u.getLogin().equals(login)) {
				return u.getUserID();
			}
		}

		return "Usuario nao encontrado";
	}

	public String getUserNameByLogin(String login) throws Exception {
		if (login == null || login.equals("")) {
			throw new Exception("Login inválido");
		}

		for (User u : users) {
			if (u.getLogin().equals(login)) {
				return u.getUserName();
			}
		}

		throw new Exception("Usuário inexistente");
	}

	public String getAddressByLogin(String login) throws Exception {
		if (login == null || login.equals("")) {
			throw new Exception("Login inválido");
		}
		for (User u : users) {
			if (u.getLogin().equals(login)) {
				return u.getAddress();
			}
		}
		throw new Exception("Usuário inexistente");
	}

	public String getItemAtributeByID(String idItem, String atribute)
			throws Exception {
		if (idItem == null || idItem.equals("")) {
			throw new Exception("Identificador do item é inválido");
		}
		if (atribute == null || atribute.equals("")) {
			throw new Exception("Atributo inválido");
		}

		for (Item i : items) {
			if (i.getItemID().equals(idItem)) {

				if (atribute.equals("nome")) {
					return i.getItemName();
				} else if (atribute.equals("descricao")) {
					return i.getItemDescription();
				} else if (atribute.equals("categoria")) {
					return i.getCategory();
				} else {
					throw new Exception("Atributo inexistente");
				}

			}

		}

		throw new Exception("Item inexistente");
	}

	public String searchUserByAtribute(String idSession, String key,
			String atribute) throws Exception {
		if (idSession == null || idSession.equals("")) {
			throw new Exception("Sessão inválida");
		}
		if (key == null || key.equals("")) {
			throw new Exception("Palavra-chave inválida");
		}
		if (atribute == null || atribute.equals("")) {
			throw new Exception("Atributo inválido");
		}

		for (User u : users) {

			if (u.getUserID().equals(idSession)) {
				if (atribute.equals("nome")) {
					return searchUserByName(key, idSession);
				} else if (atribute.equals("endereco")) {
					return searchUserByAddress(key, idSession);
				} else {
					throw new Exception("Atributo inexistente");
				}
			}
		}

		throw new Exception("Sessão inexistente");
	}

	private String searchUserByName(String key, String idSession)
			throws Exception {
		String saida = "";

		for (User u : users) {

			if (u.getUserName().contains(key)) {

				if (u.getUserID().equals(idSession)) {

					return "Nenhum usuário encontrado";
				} else {
					saida += u.getUserName() + " - " + u.getAddress() + "; ";
				}

			}
		}
		saida.trim();
		return saida.substring(0, saida.length() - 2);
	}

	private String searchUserByAddress(String key, String idSession)
			throws Exception {

		String saida = "";

		for (User u : users) {
			if (!u.getUserID().equals(idSession)) {

				if (u.getAddress().contains(key)) {

					saida += u.getUserName() + " - " + u.getAddress() + "; ";
				}
			}
		}

		if (saida.equals("")) {
			return "Nenhum usuário encontrado";
		}

		saida.trim();
		return saida.substring(0, saida.length() - 2);
	}

	public void requestFriendship(String idSession, String login)
			throws Exception {
		if (idSession == null || idSession.equals("")) {
			throw new Exception("Sessão inválida");
		}

		if (login == null || login.equals(""))
			throw new Exception("Login inválido");

		if (!idSession.matches("^[0-9]*$"))
			throw new Exception("Sessão inexistente");

		int countNoUser = 0;

		for (int i = 0; i < users.size(); i++) {
			if (!users.get(i).getLogin().equals(login))
				countNoUser += 1;
		}

		if (countNoUser == users.size())
			throw new Exception("Usuário inexistente");

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				for (User friendR : users) {
					if (friendR.getLogin().equals(login)) {
						if (!user.getFriends().contains(friendR)) {
							if (!user.getFriendshipRequestsByThis().contains(
									friendR)
									|| !friendR.getFriendshipRequests()
											.contains(user)) {
								user.getFriendshipRequestsByThis().add(friendR);
								friendR.getFriendshipRequests().add(user);
							} else
								throw new Exception(
										"Requisição já solicitada");
						} else
							throw new Exception("Os usuários já são amigos");
					}
				}

			}
		}
	}

	public String getFriendshipRequests(String idSession) throws Exception {
		if (idSession == null || idSession.equals("")) {
			throw new Exception("Sessão inválida");
		}

		if (!idSession.matches("^[0-9]*$"))
			throw new Exception("Sessão inexistente");

		String friendship = "";

		for (User u : users) {
			if (u.getUserID().equals(idSession)) {
				for (User friendR : u.getFriendshipRequests()) {
					friendship += friendR.getLogin() + "; ";
				}
			}
		}
		if (friendship.equals("")) {
			return "Não há requisições";
		}

		friendship.trim();
		return friendship.substring(0, friendship.length() - 2);
	}

	public boolean isFriend(String idSession, String login) throws Exception {
		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (login == null || login.equals(""))
			throw new Exception("Login inválido");

		if (!idSession.matches("^[0-9]*$"))
			throw new Exception("Sessão inexistente");

		int countNoUser = 0;

		for (int i = 0; i < users.size(); i++) {
			if (!users.get(i).getLogin().equals(login))
				countNoUser += 1;
		}

		if (countNoUser == users.size())
			throw new Exception("Usuário inexistente");

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				for (int i = 0; i < user.getFriends().size(); i++) {
					if (user.getFriends().get(i).getLogin().equals(login))
						return true;
				}
			}
		}
		return false;
	}

	public void acceptFriendship(String idSession, String login)
			throws Exception {
		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (login == null || login.equals(""))
			throw new Exception("Login inválido");

		if (!idSession.matches("^[0-9]*$"))
			throw new Exception("Sessão inexistente");

		int countNoUser = 0;

		for (int i = 0; i < users.size(); i++) {
			if (!users.get(i).getLogin().equals(login))
				countNoUser += 1;
		}

		if (countNoUser == users.size())
			throw new Exception("Usuário inexistente");

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				for (User friend : users) {
					if (friend.getLogin().equals(login)) {
						if (!user.getFriends().contains(friend)) {
							if (!user.getFriendshipRequestsByThis().contains(
									friend)
									|| !friend.getFriendshipRequests()
											.contains(user)) {
								user.addFriend(friend);
								friend.addFriend(user);
							} else
								throw new Exception(
										"Requisição de amizade inexistente");
						} else
							throw new Exception("Os usuários já são amigos");
					}
				}
			}
		}
	}

	public String getFriends(String idSession) throws Exception {
		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (!idSession.matches("^[0-9]*$"))
			throw new Exception("Sessão inexistente");

		String response = "";

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				if (user.getFriends().size() == 0)
					return "O usuário não possui amigos";
				else {
					for (User friends : user.getFriends()) {
						response += friends.getLogin() + "; ";
					}
				}
			}
		}
		return response = response.substring(0, response.length() - 2);
	}

	public String getFriends(String idSession, String login) throws Exception {
		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (login == null || login.equals(""))
			throw new Exception("Login inválido");

		if (!idSession.matches("^[0-9]*$"))
			throw new Exception("Sessão inexistente");

		if (!containsUser(login)) {
			throw new Exception("Usuário inexistente");
		}

		String response = "";

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				for (User u : users) {
					if (u.getLogin().equals(login)) {
						for (User friend : u.getFriends()) {
							response += friend.getLogin() + "; ";
						}
					}
				}
			}
		}

		if (response.equals("")) {
			return "O usuário não possui amigos";

		}

		response = response.substring(0, response.length() - 2);

		return response;
	}

	public String getItems(String idSession) throws Exception {
		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (!idSession.matches("^[0-9]*$"))
			throw new Exception("Sessão inexistente");

		String response = "";

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				if (user.getMyItens().size() == 0)
					return "O usuário não possui itens cadastrados";
				else {
					for (Item items : user.getMyItens()) {
						response += items.getItemName() + "; ";
					}
				}
			}
		}

		response = response.substring(0, response.length() - 2);

		return response;
	}

	public String getItems(String idSession, String login) throws Exception {
		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (!idSession.matches("^[0-9]*$"))
			throw new Exception("Sessão inexistente");

		if (login == null || login.equals(""))
			throw new Exception("Login inválido");

		if (!containsUser(login)) {
			throw new Exception("Usuário inexistente");
		}

		String response = "";

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				if (!user.isFriend(login)) {
					throw new Exception(
							"O usuário não tem permissão para visualizar estes itens");
				}
				for (User friend : user.getFriends()) {
					if (friend.getLogin().equals(login)) {
						for (Item item : friend.getMyItens()) {
							response += item.getItemName() + "; ";
						}
					}
				}
			}
		}

		if (response.equals("")) {
			return "O usuário não possui itens cadastrados";
		}

		response = response.substring(0, response.length() - 2);

		return response;
	}

	public String sendMessage(String idSession, String receiver,
			String subject, String message) throws Exception {
		String usersMessages = "";
		String receivers = "";

		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (receiver == null || receiver.equals(""))
			throw new Exception("Destinário inválido");

		if (subject == null || subject.equals(""))
			throw new Exception("Assunto inválido");

		if (message == null || message.equals(""))
			throw new Exception("Mensagem inválida");

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				if (!offTopicMessages.containsKey(subject)) {
					usersMessages += message;
					receivers += receiver;
				}

				else {
					for (int i = 0; i < offTopicMessages.get(subject).length; i++) {
						usersMessages = offTopicMessages.get(subject)[0];
						receivers = offTopicMessages.get(subject)[1];
					}
					usersMessages += "; " + message;
					receivers += receiver;
				}

				String[] messageAndReceiver = { usersMessages, receivers };
				offTopicMessages.put(subject, messageAndReceiver);
				allMessages.put(subject, messageAndReceiver);
			}
		}

		return usersMessages;
	}

	public String sendMessage(String idSession, String receiver,
			String subject, String message, String idLoanRequisition)
			throws Exception {
		String usersMessages = "";
		String receivers = "";

		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (receiver == null || receiver.equals(""))
			throw new Exception("Destinário inválido");

		if (subject == null || subject.equals(""))
			throw new Exception("Assunto inválido");

		if (message == null || message.equals(""))
			throw new Exception("Mensagem inválida");

		if (idLoanRequisition == null || idLoanRequisition.equals("")) {
			throw new Exception("Requisição inválida");
		}

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				if (!borrowingMessages.containsKey(subject)) {
					usersMessages += message;
					receivers += receiver;
				}

				else {
					for (int i = 0; i < borrowingMessages.get(subject).length; i++) {
						usersMessages = borrowingMessages.get(subject)[0];
						receivers = borrowingMessages.get(subject)[1];
					}
					usersMessages += "; " + message;
					receivers += receiver;
				}

				String[] messageAndReceiver = { usersMessages, receivers };
				borrowingMessages.put(subject, messageAndReceiver);
				allMessages.put(subject, messageAndReceiver);
			}
		}

		return usersMessages;
	}

	public String readTopics(String idSession, String type) throws Exception {
		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (type == null || type.equals(""))
			throw new Exception("Tipo inválido");

		String usersSubjects = "";
		int countSubjects = 1;

		for (User user : users) {
			if (user.getUserID().equals(idSession)) {
				usersSubjects = "";
				if (type.equals("negociacao")) {
					if (borrowingMessages.size() == 0)
						usersSubjects = "Não há tópicos criados";
					else {
						for (String subjects : borrowingMessages.keySet()) {
							if (countSubjects == borrowingMessages.size())
								usersSubjects += subjects;
							else
								usersSubjects += subjects + "; ";
							countSubjects += 1;
						}
					}
				}

				else if (type.equals("offtopic")) {
					if (offTopicMessages.size() == 0)
						usersSubjects = "Não há tópicos criados";
					else {
						countSubjects = 1;
						for (String subjects : offTopicMessages.keySet()) {
							if (countSubjects == offTopicMessages.size())
								usersSubjects += subjects;
							else
								usersSubjects += subjects + "; ";
							countSubjects += 1;
						}

					}
				} else {
					if (allMessages.size() == 0)
						usersSubjects = "Não há tópicos criados";
					else {
						countSubjects = 1;
						for (String subjects : allMessages.keySet()) {
							if (countSubjects == allMessages.size())
								usersSubjects += subjects;
							else
								usersSubjects += subjects + "; ";
							countSubjects += 1;
						}

					}
				}
			}
		}

		return usersSubjects;
	}

	public String readMessage(String idSession, String idTopic)
			throws Exception {
		if (idSession == null || idSession.equals(""))
			throw new Exception("Sessão inválida");

		if (idTopic == null || idTopic.equals(""))
			throw new Exception("Identificador do tópico é inválido");

		String userMessage = "";

		for (User u : users) {
			if (u.getUserID().equals(idSession)) {
				for (String[] topics : offTopicMessages.values()) {
					userMessage += topics[0];
				}
				return userMessage;
			}
		}

		return null;
	}

	public String itemRequest(String idSession, String idItem, int duration)
			throws Exception {
		if (idSession == null || idSession.equals("")) {
			throw new Exception("Sessão inválida");
		}

		if (idItem == null || idItem.equals("")) {
			throw new Exception("Item inválido");
		}

		if (duration <= 0) {
			throw new Exception("Duração inválida");
		}

		User borrower = idSessionCheck(idSession);

		if (borrower == null) {
			throw new Exception();
		}

		for (User u : users) {
			for (Item item : u.getMyItens()) {
				if (item.getItemID().equals(idItem)) {

					if (item.isAvailable()) {

						u.getMyRequestedItens().add(item);

					} else {
						return null;
					}
				}
			}
		}

		for (Item item : items) {
			if (item.getItemID().equals(idItem)) {

				RequestItem request = new RequestItem(borrower, item, duration);
				borrower.getItemRequests().add(request);
				return request.getIdRequest();

			}
		}

		return null;
	}

	public String approveRequest(String idSession, String idBorrowingRequest)
			throws Exception {
		if (idSession == null || idSession.equals("")) {
			throw new Exception("Sessão inválida");
		}
		if (idBorrowingRequest == null || idBorrowingRequest.equals("")) {
			throw new Exception();
		}

		User owner = idSessionCheck(idSession);

		if (owner == null) {
			throw new Exception();
		}

		for (RequestItem request : requests) {
			if (request.getIdRequest().equals(idBorrowingRequest)) {
				request.setApprove(true);

				Borrowing borrowing = new Borrowing(owner,
						request.getBorrower(), request.getItem(),
						request.getDuration());

				borrowing.setStatus("andamento");
				borrowings.add(borrowing);

				owner.getMyBorrowingsAsOwner().add(borrowing);
				request.getBorrower().getMyBorrowingsAsBorrower()
						.add(borrowing);
				return borrowing.getIdBorrowing();
			}
		}

		return null;
	}

	/**
	 * Verifica se o login passado como parametro existe no sistema.
	 * 
	 * @param login
	 * @return
	 */
	public boolean containsUser(String login) {
		boolean response = false;
		for (User u : users) {
			if (u.getLogin().equals(login)) {
				response = true;
			}
		}
		return response;
	}

	/**
	 * retorna o objeto do tipo User que possui o idSession passado como
	 * parametro.
	 * 
	 * @param idSession
	 * @return
	 */
	public User idSessionCheck(String idSession) {
		for (User u : users) {
			if (u.getUserID().equals(idSession)) {
				return u;
			}
		}
		return null;
	}

	/**
	 * retorna uma String que representa os emprestimos relacionados com o dono
	 * do idSession.
	 * 
	 * @param idSession
	 * @param type
	 * @return
	 */
	public String getBorrowings(String idSession, String type) {
		User user = idSessionCheck(idSession);

		String response = "";

		if (type.equals("emprestador")) {
			for (Borrowing borrowing : user.getMyBorrowingsAsOwner()) {
				response += borrowing.toString() + "; ";
			}

		}
		if (type.equals("beneficiado")) {
			for (Borrowing borrowing : user.getMyBorrowingsAsBorrower()) {
				response += borrowing.toString() + ": ";
			}

		}
		if (type.equals("todos")) {
			for (Borrowing borrowing : user.getMyBorrowingsAsOwner()) {
				response += borrowing.toString() + "; ";
			}
			for (Borrowing borrowing : user.getMyBorrowingsAsBorrower()) {
				response += borrowing.toString() + ": ";
			}
		}

		if (response.equals("")) {
			return "Não há empréstimos deste tipo";
		}

		return response;
	}

	public String itemReturn(String idSession, String idBorrowing)
			throws Exception {
		if (idSession == null || idSession.equals("")) {
			throw new Exception("Sessão inválida");
		}

		if (idBorrowing == null || idBorrowing.equals("")) {
			throw new Exception("Identificador do empréstimo é inválido");
		}

		User u = idSessionCheck(idSession);
		if (u == null) {
			throw new Exception("Sessão inexistente");
		}

		for (Borrowing borrowing : borrowings) {
			if (borrowing.getIdBorrowing().equals(idBorrowing)) {

			}
		}

		return null;
	}

	public String endBorrowingVerification(String idSession, String idBorrowing)
			throws Exception {
		if (idSession == null || idSession.equals("")) {
			throw new Exception("Sessão inválida");
		}
		if (idBorrowing == null || idBorrowing.equals("")) {
			throw new Exception("Identificador do empréstimo é inválido");
		}

		return null;
	}

	public void setRequests(ArrayList<RequestItem> requests) {
		this.requests = requests;
	}

	public ArrayList<RequestItem> getRequests() {
		return requests;
	}

}
